#include <2025Linux.h>
int main(int argc, char *argv[])
{
    // ./01_server_epoll 192.168.72.128 12345
    ARGS_CHECK(argc,3);
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(sockfd,-1,"socket");
    int flag = 1;
    int ret = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
    ERROR_CHECK(ret,-1,"setsockopt");
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    ret = bind(sockfd,(struct sockaddr *)&addr, sizeof(addr));
    ERROR_CHECK(ret,-1,"bind");
    ret = listen(sockfd, 10);
    ERROR_CHECK(ret,-1,"listen");
    int netfd = accept(sockfd,NULL,NULL);
    printf("client is connected!netfd1 = %d\n", netfd);

    // 申请和epoll相关的数据结构
    int epfd = epoll_create(1);
    // 设置监听 netfd和stdin
    struct epoll_event events;//记录将来fd就绪之后，往就绪队列里面放的信息
    events.events = EPOLLIN;//说明STDIN是读就绪
    events.data.fd = STDIN_FILENO; //将来fd就绪之后，把文件描述符填入队列
    epoll_ctl(epfd,EPOLL_CTL_ADD,STDIN_FILENO,&events);//设置stdin的监听
    // epoll_ctl events是一个传入传出参数，内容可能会被改掉
    events.events = EPOLLIN;//说明netfd读就绪
    events.data.fd = netfd;//说明将来netfd就绪之后，把netfd数值填入就绪集合
    epoll_ctl(epfd,EPOLL_CTL_ADD,netfd,&events);//设置netfd的监听

    struct epoll_event readyset[1024];//给将来的就绪集合申请空间
    char buf[4096];
    while(1){
        int readynum = epoll_wait(epfd,readyset,1024,-1);
        // 当运行到这一行 说明有就绪的
        for(int i = 0; i < readynum; ++i){
            // select和epoll最大区别
            // select: 根据监听的fd数量，执行多次FD_ISSET
            // epoll:  根据readynum，执行多次操作
            if(readyset[i].data.fd == STDIN_FILENO){
                memset(buf,0,sizeof(buf));
                read(STDIN_FILENO,buf,sizeof(buf));
                send(netfd,buf,strlen(buf),0);
            }
            else if(readyset[i].data.fd == netfd){
                memset(buf,0,sizeof(buf));
                recv(netfd,buf,sizeof(buf),0);
                printf("buf = %s\n", buf);
            }
        }
    }
    return 0;
}

